package com.cpit.qualitycontrol.service.impl;

import com.cpit.platform.common.constant.SystemConstant;
import com.cpit.platform.common.entity.TableDataQueryCondition;
import com.cpit.platform.common.entity.TableJsonData;
import com.cpit.platform.common.utils.Encodes;
import com.cpit.platform.common.utils.FileUtil;
import com.cpit.platform.config.GlobalConfig;
import com.cpit.platform.config.UploadPathConfig;
import com.cpit.platform.dto.User;
import com.cpit.platform.log.LogOperator;
import com.cpit.platform.security.service.UserInfo;
import com.cpit.qualitycontrol.dao.ProcessRuleRepository;
import com.cpit.qualitycontrol.dao.ProcessRuleToImageFileRepository;
import com.cpit.qualitycontrol.dao.SubTaskCrudRepository;
import com.cpit.qualitycontrol.dao.WorkOrderTypeRepository;
import com.cpit.qualitycontrol.dao.jpqlquery.ProcessRuleQueryRepository;
import com.cpit.qualitycontrol.entity.*;
import com.cpit.qualitycontrol.service.ProcessRuleService;
import com.cpit.qualitycontrol.service.ProjectService;
import com.cpit.qualitycontrol.service.UserToProductLineService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * Created by Hull on 2017/9/30.
 *
 * @author Hull
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class ProcessRuleServiceImpl implements ProcessRuleService {
    private final String loggerName = this.getClass().getName();

    private final String imageFilePath = "/System/ProcessRule";

    @Autowired
    private ProcessRuleRepository rep = null;

    @Autowired
    private ProcessRuleQueryRepository processRuleQueryRepository = null;

    @Autowired
    private ProcessRuleToImageFileRepository processRuleToImageFileRepository = null;

    @Autowired
    private WorkOrderTypeRepository workOrderTypeRepository = null;

    @Autowired
    private SubTaskCrudRepository subTaskCrudRepository = null;

    @Autowired
    private UploadPathConfig uploadPathConfig;

    @Autowired
    private GlobalConfig globalConfig;


    @Autowired
    private UserToProductLineService userToProductLineService;

    @Autowired
    private ProjectService projectService;

    @Override
    public ProcessRule findById(Long id) {
        ProcessRule processRule = this.processRuleQueryRepository.findById(id);
        if (processRule != null) {
            processRule.setProcessRuleToImageFileList(this.processRuleToImageFileRepository.findByProcessRuleIdOrderById(id));
        }
        return processRule;
    }

    @Override
    public ProcessRule copy(Long id) {
        ProcessRule processRule = this.processRuleQueryRepository.findById(id);
        ProcessRule newP = new ProcessRule();
        List<ProcessRuleToImageFile> processRuleToImageFileListTmp = new ArrayList<>();
        if (processRule != null) {
            processRule.setProcessRuleToImageFileList(this.processRuleToImageFileRepository.findByProcessRuleIdOrderById(id));
        }
        for (ProcessRuleToImageFile processRuleToImageFile : processRule.getProcessRuleToImageFileList()) {
            ProcessRuleToImageFile newI = new ProcessRuleToImageFile();
            newI.setProcessRuleId(processRuleToImageFile.getProcessRuleId());
            newI.setDownPath(processRuleToImageFile.getDownPath());
            newI.setDeletePath(processRuleToImageFile.getDeletePath());
            newI.setDescription(processRuleToImageFile.getDescription());
            newI.setId(processRuleToImageFile.getId());
            processRuleToImageFileListTmp.add(newI);
        }
        newP.setName(processRule.getName());
        newP.setDescription(processRule.getDescription());
        newP.setDeviceTypeId(processRule.getDeviceTypeId());
        newP.setDeviceTypeName(processRule.getDeviceTypeName());
        newP.setProjectId(processRule.getProjectId());
        newP.setWorkOrderTypeId(processRule.getWorkOrderTypeId());
        newP.setWorkOrderTypeName(processRule.getWorkOrderTypeName());
        newP.setPhotoCount(processRule.getPhotoCount());
        newP.setAdditionalBusinessId(processRule.getAdditionalBusinessId());
        newP.setProcessRuleToImageFileList(processRuleToImageFileListTmp);
        newP.setId(processRule.getId());
        newP.setProjectName(processRule.getProjectName());
        for (ProcessRuleToImageFile processRuleToImageFile : newP.getProcessRuleToImageFileList()) {
            try {
                copyImageFile(processRuleToImageFile);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return newP;

    }

    @Override
    public ProcessRule findByProcessRuleByDeviceTypeOrderTypeProject(Long deviceTypeId, Long workOrderTypeId, Long projectId) {
        List<ProcessRule> processRuleList = this.processRuleQueryRepository.findByCondition(null, deviceTypeId, workOrderTypeId, projectId);
        if (processRuleList.isEmpty()) {
            return null;
        }
        ProcessRule processRule = processRuleList.get(0);
        processRule.setProcessRuleToImageFileList(this.processRuleToImageFileRepository.findByProcessRuleIdOrderById(processRule.getId()));
        return processRule;
    }

    @Override
    public List<String> findOrderTypeIdsNotExistProcessRule(Long deviceTypeId, String workOrderTypeIds, Long projectId) {
        String[] strWorkOrderTypeIds = workOrderTypeIds.split(",");
        List<Long> workOrderTypeIdList = new ArrayList<>();
        for (String workOrderTypeId : strWorkOrderTypeIds) {
            Long lVal = Long.valueOf(workOrderTypeId);
            if (!workOrderTypeIdList.contains(lVal)) {
                workOrderTypeIdList.add(lVal);
            }
        }

        List<ProcessRule> processRuleList = this.processRuleQueryRepository.findByDeviceTypeOrderTypesProject(deviceTypeId, workOrderTypeIds, projectId);
        for (ProcessRule processRule : processRuleList) {
            Long workOrderTypeId = processRule.getWorkOrderTypeId();
            if (workOrderTypeIdList.contains(workOrderTypeId)) {
                workOrderTypeIdList.remove(workOrderTypeId);
            }
        }
        List<WorkOrderType> workOrderTypeList = this.workOrderTypeRepository.findWorkOrderTypeByIdIn(workOrderTypeIdList);
        List<String> workOrderTypeNameList = new ArrayList<>();
        for (WorkOrderType workOrderType : workOrderTypeList) {
            workOrderTypeNameList.add(workOrderType.getName());
        }

        return workOrderTypeNameList;
    }

    @Override
    public List<ProcessRule> findAll() {
        return this.processRuleQueryRepository.findByCondition(null, null, null, null);
    }

    @Override
    public ProcessRule create(ProcessRule processRule) throws Exception {
        if (processRule == null) {
            throw new Exception("参数为空");
        }
        if (processRule.getId() != null && processRule.getId() > 0) {
            LogOperator.info(loggerName, "流程规则ID已赋值");
            processRule.setId(0L);
        }

        this.checkUniqueConstraint(processRule);
        ProcessRule processRuleRet = this.rep.save(processRule);

        List<ProcessRuleToImageFile> processRuleToImageFileList = processRule.getProcessRuleToImageFileList();
        if (processRuleToImageFileList != null && !processRuleToImageFileList.isEmpty()) {
            for (ProcessRuleToImageFile processRuleToImageFile : processRule.getProcessRuleToImageFileList()) {
                processRuleToImageFile.setProcessRuleId(processRuleRet.getId());
                this.handleImageFile(processRuleToImageFile);
            }
            this.processRuleToImageFileRepository.save(processRule.getProcessRuleToImageFileList());
        }

        return processRuleRet;
    }

    @Override
    public ProcessRule modify(ProcessRule processRule) throws Exception {
        if (processRule == null) {
            throw new Exception("参数为空");
        }
        ProcessRule processRule1 = this.findById(processRule.getId());
        if (processRule1 == null) {
            LogOperator.info(loggerName, "修改的流程规则不存在:" + processRule);
            throw new Exception("修改的流程规则不存在");
        }

        this.checkUniqueConstraint(processRule);

        List<ProcessRuleToImageFile> processRuleToImageFileList = processRule.getProcessRuleToImageFileList();
        List<ProcessRuleToImageFile> oldProcessRuleToImageFileList = processRule1.getProcessRuleToImageFileList();
        for (ProcessRuleToImageFile processRuleToImageFile : oldProcessRuleToImageFileList) {
            if (getProcessRuleToImageFileById(processRuleToImageFileList, processRuleToImageFile.getId()) == null) {
                this.deleteImageFile(processRuleToImageFile);
                this.processRuleToImageFileRepository.delete(processRuleToImageFile.getId());
            }
        }

        if (processRuleToImageFileList != null && !processRuleToImageFileList.isEmpty()) {
            for (ProcessRuleToImageFile processRuleToImageFile : processRuleToImageFileList) {
                Long id = processRuleToImageFile.getId();
                if (id != null && id.longValue() > 0) {
                    ProcessRuleToImageFile processRuleToImageFile1 = this.getProcessRuleToImageFileById(oldProcessRuleToImageFileList, id);
                    if (processRuleToImageFile1 != null && !processRuleToImageFile1.getDownPath().equals(processRuleToImageFile.getDownPath())) {
                        this.deleteImageFile(processRuleToImageFile1);
                    }
                }
                this.handleImageFile(processRuleToImageFile);
                this.processRuleToImageFileRepository.save(processRuleToImageFile);
            }
        }
        return this.rep.save(processRule);
    }


    private ProcessRuleToImageFile getProcessRuleToImageFileById(List<ProcessRuleToImageFile> processRuleToImageFileList, Long id) {
        for (ProcessRuleToImageFile processRuleToImageFile : processRuleToImageFileList) {
            if (id.equals(processRuleToImageFile.getId())) {
                return processRuleToImageFile;
            }
        }
        return null;
    }

    @Override
    public void delete(ProcessRule processRule) throws Exception {
        if (processRule == null) {
            throw new Exception("参数为空");
        }
        this.delete(processRule.getId());
    }

    @Override
    public void delete(Long id) throws Exception {
        ProcessRule pr = this.findById(id);
        if (pr == null) {
            LogOperator.info(loggerName, "删除的流程规则不存在:" + id);
            throw new Exception("删除的流程规则不存在");
        }

        if (this.subTaskCrudRepository.countByWorkOrderTypeIdAndDeviceTypeIdAndProjectId(pr.getWorkOrderTypeId(),
                pr.getDeviceTypeId(), pr.getProjectId()) > 0) {
            LogOperator.info(loggerName, "存在关联的工单子任务，不能删除流程规则:" + id);
            throw new Exception("存在关联的工单子任务，不能删除流程规则");
        }

        for (ProcessRuleToImageFile processRuleToImageFile : pr.getProcessRuleToImageFileList()) {
            this.deleteImageFile(processRuleToImageFile);
        }
        this.processRuleToImageFileRepository.deleteByProcessRuleId(id);
        this.rep.delete(id);
    }

    @Override
    public List<ProcessRule> findByCondition(int page, int size, String order, String orderBy, String name, Long deviceTypeId, Long workOrderTypeId) {
        if (orderBy == null || orderBy.length() == 0) {
            orderBy = "id";
        }
        Sort.Direction der = order.equals(SystemConstant.DIRECTION_ASC) ? Sort.Direction.ASC : Sort.Direction.DESC;
        PageRequest request = new PageRequest(page - 1, size, new Sort(der, orderBy));

        return this.processRuleQueryRepository.findByCondition(name, deviceTypeId, workOrderTypeId, null, request, null).getContent();
    }

    @Override
    public TableJsonData findByConditionJqg(TableDataQueryCondition cond) {
        PageRequest request = ServiceUtils.getPageRequestByTableDataQueryCondition(cond);

        Map queryCondMap = cond.getQueryCond();
        String name = (String) queryCondMap.get("name");
        String strDeviceTypeId = (String) queryCondMap.get("deviceTypeId");
        Long deviceTypeId = (strDeviceTypeId == null || strDeviceTypeId.trim().isEmpty()) ? null : Long.valueOf(strDeviceTypeId);
        String strWorkOrderTypeId = (String) queryCondMap.get("workOrderTypeId");
        Long workOrderTypeId = (strWorkOrderTypeId == null || strWorkOrderTypeId.trim().isEmpty()) ? null : Long.valueOf(strWorkOrderTypeId);

        String projectIds = null;

        List<UserToProductLine> list = userToProductLineService.findByUserId(getLoginUser().getId());
        if (list != null && list.size() > 0) {//产品线角色
            Long productLineId = new Long((long) list.get(0).getProductLineId());
            List<Project> projectList = projectService.findByCondition(1, Integer.MAX_VALUE, SystemConstant.DIRECTION_ASC, null, productLineId, null);
            if (projectList != null && projectList.size() > 0) {
                StringBuffer buf = new StringBuffer();
                for (Project p : projectList) {
                    buf.append(p.getId());
                    buf.append(",");
                }
                projectIds = buf.deleteCharAt(buf.length() - 1).toString();
            }
        }

        Page<ProcessRule> processRulePage = this.processRuleQueryRepository.findByCondition(name, deviceTypeId, workOrderTypeId, null, request, projectIds);

        return new TableJsonData(cond, processRulePage.getTotalElements(), processRulePage.getContent());
    }

    /**
     * 检查唯一性约束
     *
     * @param deviceType 设备类型Bean
     * @throws Exception
     */
    private void checkUniqueConstraint(ProcessRule processRule) throws Exception {
        ProcessRule pr = rep.findByName(processRule.getName());
        if (pr != null && !pr.getId().equals(processRule.getId())) {
            LogOperator.err(loggerName, "同名流程规则已存在:" + processRule.getName());
            throw new Exception("同名流程规则已存在");
        }


        List<ProcessRule> processRuleList = this.processRuleQueryRepository.findByCondition(null, processRule.getDeviceTypeId(), processRule.getWorkOrderTypeId(), processRule.getProjectId());
        for (ProcessRule processRule1 : processRuleList) {
            if (!processRule1.getId().equals(processRule.getId())) {
                LogOperator.err(loggerName, "对应设备类型、工单类型和项目的流程规则已存在:" + processRule.getName());
                throw new Exception("对应设备类型、工单类型和项目的流程规则已存在");
            }
        }
    }

    private void copyImageFile(ProcessRuleToImageFile processRuleToImageFile) throws Exception {
        String oldUrl = processRuleToImageFile.getDownPath();
        String fileName = oldUrl.substring(oldUrl.lastIndexOf("/") + 1, oldUrl.length());
        String NfileName = Encodes.decodeBase64String(fileName);
        String NNfileName = NfileName.substring(NfileName.lastIndexOf("/") + 1, NfileName.length());
        String newFileName = NNfileName.substring(0, NNfileName.lastIndexOf("_")) + "_" + System.currentTimeMillis() + ".jpg";
        FileUtil.copyFile(uploadPathConfig.getPath() + imageFilePath, NNfileName, uploadPathConfig.getTemp(), newFileName);
        processRuleToImageFile.setDownPath(globalConfig.getContextPath() + "/file/download/temp/" + newFileName);
        processRuleToImageFile.setDeletePath(globalConfig.getContextPath() + "/file/delete/temp/" + newFileName);

    }

    private void handleImageFile(ProcessRuleToImageFile processRuleToImageFile) throws Exception {
        String oldUrl = processRuleToImageFile.getDownPath();
        if (oldUrl.contains(uploadPathConfig.getTemp().replace(uploadPathConfig.getPath(), ""))) {
            String fileName = oldUrl.substring(oldUrl.lastIndexOf("/") + 1, oldUrl.length());
            FileUtil.moveFile(uploadPathConfig.getTemp(), fileName, uploadPathConfig.getPath() + imageFilePath, fileName);
            String newFileName = uploadPathConfig.getPath() + imageFilePath + "/" + fileName;
            processRuleToImageFile.setDownPath(uploadPathConfig.getWebDownloadBase64Path(newFileName));
            processRuleToImageFile.setDeletePath(uploadPathConfig.getWebDeleteBase64Path(newFileName));
        }
    }

    private void deleteImageFile(ProcessRuleToImageFile processRuleToImageFile) {
        String fileName = Encodes.decodeBase64String(processRuleToImageFile.getDownPath());
        (new File(uploadPathConfig.getPath() + imageFilePath, fileName.substring(fileName.lastIndexOf("/") + 1))).delete();
    }

    /**
     * 获取登录用户信息
     *
     * @return
     */
    private User getLoginUser() {
        return ((UserInfo) SecurityContextHolder.getContext()
                .getAuthentication()
                .getPrincipal()).getUser();
    }

//    public class ProcessRuleSpecification implements Specification<ProcessRule> {
//        private String name = null;
//        private Long deviceTypeId = null;
//        private Long workOrderTypeId = null;
//
//        public ProcessRuleSpecification(String name, Long deviceTypeId, Long workOrderTypeId) {
//            this.name = name;
//            this.deviceTypeId = deviceTypeId;
//            this.workOrderTypeId = workOrderTypeId;
//        }
//
//        @Override
//        public Predicate toPredicate(Root<ProcessRule> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
//            Predicate predicate = null;
//            if (name != null && !name.isEmpty()) {
//                Predicate pTmp = criteriaBuilder.like(root.get("name"), "%" + name + "%");
//                predicate = (predicate == null) ? pTmp : criteriaBuilder.and(predicate, pTmp);
//            }
//            if (deviceTypeId != null && deviceTypeId != 0) {
//                Predicate pTmp = criteriaBuilder.equal(root.get("deviceTypeId"), deviceTypeId);
//                predicate = (predicate == null) ? pTmp : criteriaBuilder.and(predicate, pTmp);
//            }
//            if (workOrderTypeId != null && workOrderTypeId != 0) {
//                Predicate pTmp = criteriaBuilder.equal(root.get("workOrderTypeId"), workOrderTypeId);
//                predicate = (predicate == null) ? pTmp : criteriaBuilder.and(predicate, pTmp);
//            }
//            return predicate;
//        }
//    }
}
